package com.linjiahao.oss.config;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.linjiahao.oss.vo.SignParaVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 国密配置文件解析工具类
 * @author suruihuang
 */
public class StateSecretSecurityConfig {
    private final static transient Logger logger = LoggerFactory.getLogger(StateSecretSecurityConfig.class);

    //key:类的class完整路径(class.getName()),value:需要加解密的字段列表
    public static Map<String, List<String>> encryptMap=new HashMap<String, List<String>>();

    //签名Map,key:类的class完整路径(class.getName())，value:需要签名的字段列表
    public static Map<String,List<SignParaVO>> signMap=new HashMap<String,List<SignParaVO>>();

    //类完整名称Set,临时缓存
    public static Set<String> classSet=new HashSet<String>();

    //涉及加解密、签名、验签的字段,临时缓存
    public static Map<String,Set<String>> classFieldMap=new HashMap<String,Set<String>>();

    //是否已经加载过
    private static Boolean isLoad=false;
    /**
     * 加载国密配置文件
     * @throws IOException
     */
    public static void loadConfigFile() {
        synchronized (isLoad){
            if(isLoad==false){
                isLoad=true;
            }else{
                return;
            }
        }


        try{
            loadEncryptConfigFile("1.json");
        }catch (Exception e){
            
        }
        try{
            loadSignConfigFile("2.json");
        }catch (Exception e){
           
        }

    }

    private static String getResourceContent(ClassPathResource cpr)  {
        String content=null;
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(cpr.getInputStream()));
            content = reader.lines().collect(Collectors.joining("\n"));
            reader.close();
        } catch (IOException ex) {
            logger.error("error:{}",ex);
        }
        return content;
    }

    private static void loadEncryptConfigFile(String filePath) {
        /*File encryptConfigFile=new File(StateSecretSecurityConfig.class.getResource("/GuoMiEncrypt-APICLIENT.json").getFile());
        if(encryptConfigFile.exists()==false){
            logger.error("classes目录缺少国密加解密配置文件GuoMiEncrypt.json");
            throw new BaseException("classes目录缺少国密加解密配置文件GuoMiEncrypt.json");
        }
        String content=readFileContent(encryptConfigFile);*/
        ClassPathResource cpr = new ClassPathResource(filePath);
        String content = "";
        content = getResourceContent(cpr);
        if (StringUtils.isEmpty(content)){
            logger.error("classes目录缺少国密加解密配置文件"+filePath);
        }
        //最外层JSON对象列表
        JSONArray jsonArray=JSONArray.parseArray(content);
        if(jsonArray!=null){
            //第2层JSON对象
            JSONObject obj=null;
            //包名,对应配置文件中的package节点
            String packageStr=null;
            //类列表,对应配文件中的classes节点
            JSONArray classes=null;
            //classes节点下的类JSON对象
            JSONObject classObj=null;
            //类名,对应配置文件中的className节点
            String className=null;
            //需要加解密的字段列表,对应配置文件中的securityFields节点
            JSONArray securityFields=null;
            //需要加解密的字段Set
            Set<String> classFieldSet=null;
            //需要加解密的字段List
             List<String> fieldNameList=null;
            for(int i=0;i<jsonArray.size();i++){
                obj=jsonArray.getJSONObject(i);
                packageStr=obj.getString("package");
                classes=obj.getJSONArray("classes");
                if(classes!=null){
                    for(int j=0;j<classes.size();j++){
                        classObj=classes.getJSONObject(j);
                        className=classObj.getString("className");
                        securityFields=classObj.getJSONArray("securityFields");

                        if(securityFields!=null&&securityFields.size()>0){
                            fieldNameList=securityFields.toJavaList(String.class);
                            //需要加解密的类字段
                            encryptMap.put(packageStr+"."+className,fieldNameList);

                            //需要加解密、签名、验签的类完整路径
                            classSet.add(packageStr+"."+className);

                            //需要加解密、签名、验签的字段
                            classFieldSet=classFieldMap.get(packageStr+"."+className);
                            if(classFieldSet==null){
                                classFieldSet=new HashSet<String>();
                                classFieldMap.put(packageStr+"."+className,classFieldSet);
                            }
                            classFieldSet.addAll(fieldNameList);
                        }


                    }
                }

            }
        }
    }

    /**
     * 获取文件内容
     * @param file
     * @return
     * @throws IOException
     */
    private static String readFileContent(File file) throws IOException {
        StringBuilder content=new StringBuilder();
        FileInputStream fis =null;
        BufferedReader br=null;
        try{
            fis = new FileInputStream(file); // filePath是自定义路径str
            // 指定编码格式
            br = new BufferedReader(new InputStreamReader(fis, "utf-8"));
            String line = null;
            while ((line = br.readLine()) != null) {
                content.append(line);
            }
            return content.toString();
        }catch (IOException e){
            if(br!=null){
                try{
                    br.close();
                }catch (Exception e1){
                }
            }
            if(fis!=null){
                try{
                    fis.close();
                }catch (Exception e1){
                }
            }
            throw  e;
        }
    }

    private static void loadSignConfigFile(String filePath){
        /*File guoMiSignConfigFile=new File(StateSecretSecurityConfig.class.getResource("/GuoMiSign.json").getFile());
        if(guoMiSignConfigFile.exists()==false){
            logger.error("classes目录缺少国密签名配置文件GuoMiSign.json");
            throw new BaseException("classes目录缺少国密签名配置文件GuoMiSign.json");
        }
        String content=readFileContent(guoMiSignConfigFile);*/
        ClassPathResource cpr = new ClassPathResource(filePath);
        String content = "";
        content = getResourceContent(cpr);
        if (StringUtils.isEmpty(content)){
            logger.error("classes目录缺少国密签名配置文件"+filePath);
        }
        //最外层JSON对象列表
        JSONArray jsonArray=JSONArray.parseArray(content);
        //agentCode
        String agentCode=null;
        //tableName,数据库表名或ES索引名,用于拼接ES ID
        String tableName=null;
        //dbField,数据库字段名称,用于拼接ES ID
        String dbField=null;
        //第2层JSON对象
        JSONObject obj=null;
        JSONArray signClasses=null;
        //signClasses数组下的JSON对象
        JSONObject signClass=null;
        //类名，含完整包路径
        String name=null;
        //主键字段名(驼峰)
        String pkField=null;
        //需要签名和验签的字段名(驼峰)
        String signField=null;
        SignParaVO signParaVO=null;
        List<SignParaVO> signParaVOList=null;
        //需要加解密的字段Set
        Set<String> classFieldSet=null;
        if(jsonArray!=null){
            for(int i=0;i<jsonArray.size();i++){
                obj=jsonArray.getJSONObject(i);
                agentCode=obj.getString("agentCode");
                tableName=obj.getString("tableName");
                dbField=obj.getString("dbField");
                signClasses=obj.getJSONArray("signClasses");
                if(signClasses!=null){
                    for(int j=0;j<signClasses.size();j++){
                        signClass=signClasses.getJSONObject(j);

                        name=signClass.getString("name");
                        pkField=signClass.getString("pkField");
                        signField=signClass.getString("signField");

                        signParaVO=new SignParaVO();
                        signParaVO.setSignField(signField);
                        signParaVO.setAgentCode(agentCode);
                        signParaVO.setTableName(tableName);
                        signParaVO.setDbField(dbField);
                        signParaVO.setPkField(pkField);

                        signParaVOList=signMap.get(name);
                        if(signParaVOList==null){
                            signParaVOList=new ArrayList<SignParaVO>();
                            signMap.put(name,signParaVOList);
                        }
                        signParaVOList.add(signParaVO);

                        //需要加解密、签名、验签的类完整路径
                        classSet.add(name);

                        //需要加解密、签名、验签的字段
                        classFieldSet=classFieldMap.get(name);
                        if(classFieldSet==null){
                            classFieldSet=new HashSet<String>();
                            classFieldMap.put(name,classFieldSet);
                        }
                        classFieldSet.add(pkField);
                        classFieldSet.add(signField);
                    }
                }
            }
        }
    }

    /**
     * 释放临时缓存
     */
    public static void clear(){
        classSet.clear();
        classFieldMap.clear();
        classSet=null;
        classFieldMap=null;
    }

    public static void main(String args[]){
        try {
            loadConfigFile();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
